package com.panopset.flywheel.gui;

import static com.panopset.Util.*;
import static com.panopset.UtilIO.*;

import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.io.StringWriter;
import java.util.Vector;

import javax.swing.JTabbedPane;

import com.panopset.flywheel.Command;
import com.panopset.flywheel.Flywheel;
import com.panopset.flywheel.MatchableCommand;
import com.panopset.gui.LookAndFeel;
import com.panopset.gui.Osgw;
import com.panopset.gui.TPanel;

/**
 * Debugging infrastructure for Flywheel.
 *
 * @author Karl Dinwiddie
 */
public final class FlywheelInfrastruture {

    /**
     * Flywheel instance.
     */
    private Flywheel f;

    /**
     * Infrastructure panel.
     */
    private TPanel panel;

    /**
     * Debug a Flywheel instance.
     *
     * @param flywheel
     *            Flywheel.
     */
    public void setFlywheel(final Flywheel flywheel) {
        f = flywheel;
    }

    /**
     * @return Main panel.
     */
    public TPanel getPanel() {
        if (panel == null) {
            panel = new TPanel.Builder().layout(new GridLayout(1, 1))
                    .construct();
            JTabbedPane views = new JTabbedPane();
            views.add(getTopCommandCanvas().getPanel());
            views.add(getSubCommandCanvas().getPanel());
            panel.add(views);
        }
        return panel;
    }

    /**
     * Background color.
     */

    /**
     * Get command title.
     *
     * @param command
     *            Command
     * @return Command title.
     */
    String getCommandTitle(final Command command) {
        StringWriter sw = new StringWriter();
        if (command == null) {
            sw.append("null command");
        } else {
            String s = command.getClass().getSimpleName();
            if (s.indexOf(COMMAND) == 0) {
                s = s.substring(COMMAND.length());
            }
            sw.append(s);
        }
        return sw.toString();
    }

    /**
     * Command.
     */
    public static final String COMMAND = "Command";

    /**
     * Top command canvas.
     */
    private TopCommandCanvas topCommandCanvas;

    /**
     * @return Top command canvas.
     */
    private TopCommandCanvas getTopCommandCanvas() {
        if (topCommandCanvas == null) {
            topCommandCanvas = new TopCommandCanvas();
            topCommandCanvas.getPanel().setName("Top Commands");
        }
        return topCommandCanvas;
    }

    /**
     * Sub command canvas.
     */
    private SubCommandCanvas subCommandCanvas;

    /**
     * @return Sub command canvas.
     */
    private SubCommandCanvas getSubCommandCanvas() {
        if (subCommandCanvas == null) {
            subCommandCanvas = new SubCommandCanvas();
            subCommandCanvas.getPanel().setName("Sub Commands");
        }
        return subCommandCanvas;
    }

    /**
     * Quit.
     */
    public void quit() {
        Osgw.close();
        if (f != null) {
            f.stop(x("Exiting application."));
        }
    }

    /**
     * Sub command canvas.
     */
    class SubCommandCanvas extends CommandCanvas {

        @Override
        public Vector<Command> getDisplayedCommands() {
            if (f.isTargetDirectoryValid()) {
                if (f.getResolvingCommand() == null) {
                    return null;
                }
                if (f.getResolvingCommand() instanceof MatchableCommand) {
                    return ((MatchableCommand) f.getResolvingCommand())
                            .getCommands();
                }
            }
            return null;
        }
    }

    /**
     * Load template from resource.
     * @param name Name of template.
     * @return Template lines.
     */
    private String[] loadTemplate(final String name) {
        return loadLineArrayFromResource(this.getClass(), name);
    }

    /**
     * Top command canvas.
     */
    class TopCommandCanvas extends CommandCanvas {

        @Override
        public Vector<Command> getDisplayedCommands() {
            if (f != null && f.isTargetDirectoryValid()) {
                return f.getTemplate().getTopCommands();
            } else {
                return new Vector<Command>();
            }
        }
    }

    /**
     * Command canvas.
     */
    abstract class CommandCanvas extends Osgw {

        /**
         * Width.
         */
        private static final int W = 1000;

        /**
         * Height.
         */
        private static final int H = 1000;

        /**
         *
         */
        public CommandCanvas() {
            super(W, H);
        }

        /**
         * @return Displayed commands.
         */
        public abstract Vector<Command> getDisplayedCommands();

        /**
         * template.
         */
        private String[] bgTmplt;

        /**
         * @return template.
         */
        private String[] getBgTmplt() {
            if (bgTmplt == null) {
                bgTmplt = loadTemplate("cmdCanvasBgd.txt");
            }
            return bgTmplt;
        }

        /**
         * template.
         */
        private String[] cmdPainter;

        /**
         * @return template.
         */
        private String[] getCmdPainterTmplt() {
            if (cmdPainter == null) {
                cmdPainter = loadTemplate("cmdPainter.txt");
            }
            return cmdPainter;
        }

        /**
         * Y base location is 40.
         */
        private static final int X_BASE = 6;

        /**
         * Y base location is 40.
         */
        private static final int Y_BASE = 40;

        /**
         * H base height is 15.
         */
        private static final int H_BASE = 15;

        /**
         * Command offset is 50.
         */
        private static final int CMD_OFFSET = 50;

        /**
         * Y offset is 18.
         */
        private static final int Y_OFFSET = 18;

        @Override
        public void paintCycle(final Graphics2D g) {

            new Flywheel.Builder().input(getBgTmplt()).registerObject("g",
                    new Artist(g)).construct().exec();

            Vector<Command> cmds = getDisplayedCommands();

            if (cmds == null || f == null || !f.isTargetDirectoryValid()) {
                return;
            }

            int x = X_BASE;
            int y = Y_BASE;
            int h = H_BASE;

            for (Command command : cmds) {
                g.setFont(LookAndFeel.Fonts.TEXT_AREA_FONT.getFont());
                String cmdbg = "777777";
                if (command == f.getResolvingCommand()) {
                    cmdbg = "ffff00";
                }
                int ry = y - h + 2;
                int x2 = x + 2;
                int x50 = x + CMD_OFFSET;
                new Flywheel.Builder().input(getCmdPainterTmplt())
                    .registerObject("g", new Artist(g))
                    .map("x", "" + x)
                    .map("x2", "" + x2)
                    .map("x50", "" + x50)
                    .map("y", "" + y)
                    .map("ry", "" + ry)
                    .map("h", "" + h)
                    .map("cmdbg", cmdbg)
                    .map("cmd", command.toString())
                    .map("title", getCommandTitle(command))
                    .construct().exec();
                y += Y_OFFSET;
            }
        }
    }
}
